/*---------------------------------------------------------------------
 * File name: hal_spi.cpp
 *
 * Copyright (c) <2020-2022>, <ChenLong>
 *
 * All rights reserved.
 *
 * Author: ChenLong
 * Email: worldlong@foxmail.com
 *--------------------------------------------------------------------*/
#include "stm32f30x_rcc.h"
#include "stm32f30x_dma.h"
#include "stm32f30x_gpio.h"
#include "stm32f30x_spi.h"
#include "stm32f30x_misc.h"
#include "hal_spi.h"
#include "hal_gpio.h"
#include "hal_system.h"
#include "hal_config.h"
#if defined(USING_RT_THREAD)
#include "rtthread.h" 
#endif
/*
*/
//SPI1 
#if SPI1_ENABLE
#if SPI1_RX_DMA == DMA1_CHANNEL2
#define SPI1_RX_DMA_CH DMA1_Channel2
#define SPI1_RX_DMA_CH_IRQN DMA1_Channel2_IRQn
#define SPI1_RX_DMA_CH_IRQH DMA1_Channel2_IRQHandler
#define SPI1_RX_DMA_IT_TC DMA1_IT_TC2
#else
#error "SPI1_RX_DMA incorrect."
#endif
#if SPI1_TX_DMA == DMA1_CHANNEL3
#define SPI1_TX_DMA_CH DMA1_Channel3
#define SPI1_TX_DMA_CH_IRQN DMA1_Channel3_IRQn
#define SPI1_TX_DMA_CH_IRQH DMA1_Channel3_IRQHandler
#define SPI1_TX_DMA_IT_TC DMA1_IT_TC3
#else
#error "SPI1_TX_DMA incorrect."
#endif
#endif
//SPI2
#if SPI2_ENABLE
#if SPI2_RX_DMA == DMA1_CHANNEL4
#define SPI2_RX_DMA_CH DMA1_Channel4
#define SPI2_RX_DMA_CH_IRQN DMA1_Channel4_IRQn
#define SPI2_RX_DMA_CH_IRQH DMA1_Channel4_IRQHandler
#define SPI2_RX_DMA_IT_TC DMA1_IT_TC4
#else
#error "SPI2_RX_DMA incorrect."
#endif
#if SPI2_TX_DMA == DMA1_CHANNEL5
#define SPI2_TX_DMA_CH DMA1_Channel5
#define SPI2_TX_DMA_CH_IRQN DMA1_Channel5_IRQn
#define SPI2_TX_DMA_CH_IRQH DMA1_Channel5_IRQHandler
#define SPI2_TX_DMA_IT_TC DMA1_IT_TC5
#else
#error "SPI2_TX_DMA incorrect."
#endif
#endif
//SPI3 
#if SPI3_ENABLE
#if SPI3_RX_DMA == DMA1_CHANNEL2
#define SPI3_RX_DMA_CH DMA1_Channel2
#define SPI3_RX_DMA_CH_IRQN DMA1_Channel2_IRQn
#define SPI3_RX_DMA_CH_IRQH DMA1_Channel2_IRQHandler
#define SPI3_RX_DMA_IT_TC DMA1_IT_TC2
#elif SPI3_RX_DMA == DMA2_CHANNEL1
#define SPI3_RX_DMA_CH DMA2_Channel1
#define SPI3_RX_DMA_CH_IRQN DMA2_Channel1_IRQn
#define SPI3_RX_DMA_CH_IRQH DMA2_Channel1_IRQHandler
#define SPI3_RX_DMA_IT_TC DMA2_IT_TC1
#else
#error "SPI3_RX_DMA incorrect."
#endif
#if SPI3_TX_DMA == DMA1_CHANNEL3
#define SPI3_TX_DMA_CH DMA1_Channel3
#define SPI3_TX_DMA_CH_IRQN DMA1_Channel3_IRQn
#define SPI3_TX_DMA_CH_IRQH DMA1_Channel3_IRQHandler
#define SPI3_TX_DMA_IT_TC DMA1_IT_TC3
#elif SPI3_TX_DMA == DMA2_CHANNEL2
#define SPI3_TX_DMA_CH DMA2_Channel2
#define SPI3_TX_DMA_CH_IRQN DMA2_Channel2_IRQn
#define SPI3_TX_DMA_CH_IRQH DMA2_Channel2_IRQHandler
#define SPI3_TX_DMA_IT_TC DMA2_IT_TC2
#else
#error "SPI3_TX_DMA incorrect."
#endif
#endif
//SPI4
#if SPI4_ENABLE
#if SPI4_RX_DMA == DMA2_CHANNEL4
#define SPI4_RX_DMA_CH DMA2_Channel4
#define SPI4_RX_DMA_CH_IRQN DMA2_Channel4_IRQn
#define SPI4_RX_DMA_CH_IRQH DMA2_Channel4_IRQHandler
#define SPI4_RX_DMA_IT_TC DMA2_IT_TC4
#else
#error "SPI4_RX_DMA incorrect."
#endif
#if SPI4_TX_DMA == DMA2_CHANNEL5
#define SPI4_TX_DMA_CH DMA2_Channel5
#define SPI4_TX_DMA_CH_IRQN DMA2_Channel5_IRQn
#define SPI4_TX_DMA_CH_IRQH DMA2_Channel5_IRQHandler
#define SPI4_TX_DMA_IT_TC DMA2_IT_TC5
#else
#error "SPI4_TX_DMA incorrect."
#endif
#endif
/*---------------------------------------------------
 *                   SPI_Object
 *---------------------------------------------------*/
class SPI_Object
{
public:
  SPI_Object(SPI_TypeDef *SPIx,
             DMA_Channel_TypeDef *DMA_Rx,
             DMA_Channel_TypeDef *DMA_Tx,
             uint8_t *dma_rx_buffer, int dma_rx_buffer_size,
             uint8_t *dma_tx_buffer, int dma_tx_buffer_size) :
    spi(SPIx),
    dma_rx(DMA_Rx),
    dma_tx(DMA_Tx),
    dma_rx_buffer(dma_rx_buffer),
    dma_tx_buffer(dma_tx_buffer),
    dma_rx_buffer_size(dma_rx_buffer_size),
    dma_tx_buffer_size(dma_tx_buffer_size),
    data_bits(8),
    rx_busy(false),
    tx_busy(false)
  {}
  
  SPI_TypeDef           *spi;
  DMA_Channel_TypeDef   *dma_rx;
  DMA_Channel_TypeDef   *dma_tx;
  uint8_t *dma_rx_buffer;
  uint8_t *dma_tx_buffer;
  uint32_t dma_rx_buffer_size;
  uint32_t dma_tx_buffer_size;
  uint8_t data_bits;
  bool rx_busy;
  bool tx_busy;
  
  void dma_rx_config();
  void dma_tx_config();
  void dma_rx_start(uint32_t number);
  void dma_tx_start(uint32_t number);
  void dma_rx_end();
  void dma_tx_end();
  bool config(uint32_t cfg);
  int transfer(uint8_t *tx_buffer, uint8_t *rx_buffer, uint32_t number);
};
/*
*/
void SPI_Object::dma_rx_config()
{
    DMA_InitTypeDef  DMA_InitStructure;
    DMA_DeInit(dma_rx);
    
    if(data_bits == 16) {
      DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&spi->DR);
    } else {
      DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)spi + 0x0c;
    }
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)dma_rx_buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize = 0;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    if(data_bits == 16) {
      DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    } else {
      DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
      DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    }
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    
    DMA_Init(dma_rx, &DMA_InitStructure);
    /* Enable DMA Stream Transfer Complete interrupt */
    DMA_ITConfig(dma_tx, DMA_IT_TC, ENABLE);
    /* DMA Stream disable first*/
    DMA_Cmd(dma_rx, DISABLE);
    SPI_I2S_DMACmd(spi, SPI_I2S_DMAReq_Rx, ENABLE);
}
/*
*/
void SPI_Object::dma_tx_config()
{
  DMA_InitTypeDef  DMA_InitStructure;
  DMA_DeInit(dma_tx);

  if(data_bits) {
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&spi->DR);
  } else {
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)spi + 0x0c;
  }
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)dma_tx_buffer;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
  DMA_InitStructure.DMA_BufferSize = 0;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  if(data_bits) {
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  } else {
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  }
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;   
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  
  DMA_Init(dma_tx, &DMA_InitStructure);
  /* Enable DMA Stream Transfer Complete interrupt */
  DMA_ITConfig(dma_rx, DMA_IT_TC, ENABLE);
  /* DMA Stream disable first*/
  DMA_Cmd(dma_tx, DISABLE);
  SPI_I2S_DMACmd(spi, SPI_I2S_DMAReq_Tx, ENABLE);
}
/*
*/
void SPI_Object::dma_rx_start(uint32_t number) 
{
  if(number > dma_rx_buffer_size) {
    number = dma_rx_buffer_size;
  }
  
  DMA_SetCurrDataCounter(dma_rx, number);
  DMA_Cmd(dma_rx, ENABLE);
  rx_busy = true;
}
/*
*/
void SPI_Object::dma_tx_start(uint32_t number) 
{
  if(number > dma_tx_buffer_size) {
    number = dma_tx_buffer_size;
  }
  
  DMA_SetCurrDataCounter(dma_tx, number);
  DMA_Cmd(dma_tx, ENABLE);
  tx_busy = true;
}
/*
*/
void SPI_Object::dma_rx_end()
{
  DMA_Cmd(dma_rx, DISABLE);
  rx_busy = false;
}
/*
*/
void SPI_Object::dma_tx_end()
{
  DMA_Cmd(dma_tx, DISABLE);
  tx_busy = false;
}
/*
*/
bool SPI_Object::config(uint32_t cfg)
{  
  SPI_InitTypeDef SPI_InitStructure;
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; 
  //mode
  uint32_t tmp = SPI_CFG_EXTRACT(cfg, MODE);
  if(tmp == SPI_MODE(MASTER)) {
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  } else if(tmp == SPI_MODE(SLAVE)) {
    SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
  } else {
    return false;
  }
  //data bits
  tmp = SPI_CFG_EXTRACT(cfg, DATA);
  if(tmp == SPI_DATA(8B)) {
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;	
    SPI_RxFIFOThresholdConfig(spi, SPI_RxFIFOThreshold_QF);
  } else if(tmp == SPI_DATA(16B)) {
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;
  } else {
    return false;
  }
  //cpol
  tmp = SPI_CFG_EXTRACT(cfg, CPOL);
  if(tmp == SPI_CPOL(HIGH)) {
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;	
  } else if(tmp == SPI_CPOL(LOW)) {
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_LOW;
  } else {
    return false;
  }
  //cpha
  tmp = SPI_CFG_EXTRACT(cfg, CPHA);
  if(tmp == SPI_CPHA(1EDGE)) {
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;	
  } else if(tmp == SPI_CPHA(2EDGE)) {
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
  } else {
    return false;
  }	  	
  //nss 
  tmp = SPI_CFG_EXTRACT(cfg, NSS);
  if(tmp == SPI_NSS(SOFT)) {
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;	
  } else if(tmp == SPI_NSS(HARD)) {
    SPI_InitStructure.SPI_NSS = SPI_NSS_Hard;
  } else {
    return false;
  }
  //FirstBit 
  tmp = SPI_CFG_EXTRACT(cfg, FB);
  if(tmp == SPI_FB(MSB)) {
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	
  } else if(tmp == SPI_FB(LSB)) {
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_LSB;
  } else {
    return false;
  }
  //BaudRatePrescaler
  tmp = SPI_CFG_EXTRACT(cfg, BRP);
  SPI_InitStructure.SPI_BaudRatePrescaler = tmp << 3;
  SPI_InitStructure.SPI_CRCPolynomial = 7;
  
  SPI_Cmd(spi, DISABLE);
  SPI_Init(spi, &SPI_InitStructure);
  SPI_Cmd(spi, ENABLE);
  return true;
}
/*
*/
int SPI_Object::transfer(uint8_t *tx_buffer, uint8_t *rx_buffer, uint32_t number)
{ 
  uint32_t sr = enter_critical();

  //Only in normal mode
  if(data_bits == 16) {
    uint16_t *tx = (uint16_t*)tx_buffer;
    uint16_t *rx = (uint16_t*)rx_buffer;
    
    while(spi->SR & 0x01){
      SPI_I2S_ReceiveData16(spi);  //clear receive buffer first
    }
     
    if(tx == nullptr) {   //Only read, no matter what send
      for(int i=0; i<number/2; i++) {
        while(!(spi->SR & 0x02));
        SPI_I2S_SendData16(spi, 0);
        while(!(spi->SR & 0x01));
        rx[i] = SPI_I2S_ReceiveData16(spi);
      }
    } else if(rx == nullptr) { //Only send, no matter what read
      for(int i=0; i<number/2; i++) {
        while(!(spi->SR & 0x02));
        SPI_I2S_SendData16(spi, tx[i]);
        while(!(spi->SR & 0x01));
        SPI_I2S_ReceiveData16(spi);
      }
    } else { //Send and read
      for(int i=0; i<number/2; i++) {
        while(!(spi->SR & 0x02));
        SPI_I2S_SendData16(spi, tx[i]);
        while(!(spi->SR & 0x01));
        rx[i] = SPI_I2S_ReceiveData16(spi);
      }
    }
  } else {
    while((spi->SR & 0x01)){
      SPI_ReceiveData8(spi);  //clear receive buffer first
    }
     
    if(tx_buffer == nullptr) { //Only read, no matter what send
      for(int i=0; i<number; i++) {
        while(!(spi->SR & 0x02));
        SPI_SendData8(spi, 0);
        while(!(spi->SR & 0x01));
        rx_buffer[i] = SPI_ReceiveData8(spi);
      }
    } else if(rx_buffer == nullptr) { //Only send, no matter what read
      for(int i=0; i<number; i++) {
        while(!(spi->SR & 0x02));
        SPI_SendData8(spi, tx_buffer[i]);
        while(!(spi->SR & 0x01));
        SPI_ReceiveData8(spi);
      }
    } else { //Send and read
      for(int i=0; i<number; i++) {
        while(!(spi->SR & 0x02));
        SPI_SendData8(spi, tx_buffer[i]);
        while(!(spi->SR & 0x01));
        rx_buffer[i] = SPI_ReceiveData8(spi);
      }
    }
  }
  exit_critical(sr);
    
  return number;
}
/*----------------------------------------
 *             SPI1 Object
 *-----------------------------------------*/
#if SPI1_ENABLE
#if SPI1_RX_DMA_ENABLE
  static uint8_t spi1_rx_dma_buffer[SPI1_RX_DMA_BUFFER_SIZE];
#else
  static uint8_t *spi1_rx_dma_buffer = nullptr;
#endif
#if SPI1_TX_DMA_ENABLE
  static uint8_t spi1_tx_dma_buffer[SPI1_TX_DMA_BUFFER_SIZE];
#else
  static uint8_t *spi1_tx_dma_buffer = nullptr;
#endif
  static SPI_Object spi1(SPI1, SPI1_RX_DMA_CH, SPI1_TX_DMA_CH,
                         spi1_rx_dma_buffer, SPI1_RX_DMA_BUFFER_SIZE,
                         spi1_tx_dma_buffer, SPI1_TX_DMA_BUFFER_SIZE);
#endif
/*----------------------------------------
 *             SPI2 Object
 *-----------------------------------------*/
#if SPI2_ENABLE
#if SPI2_RX_DMA_ENABLE
  static uint8_t spi2_rx_dma_buffer[SPI2_RX_DMA_BUFFER_SIZE];
#else
  static uint8_t *spi2_rx_dma_buffer = nullptr;
#endif
#if SPI2_TX_DMA_ENABLE
  static uint8_t spi2_tx_dma_buffer[SPI2_TX_DMA_BUFFER_SIZE];
#else
  static uint8_t *spi2_tx_dma_buffer = nullptr;
#endif
  static SPI_Object spi2(SPI2, SPI2_RX_DMA_CH, SPI2_TX_DMA_CH,
                         spi2_rx_dma_buffer, SPI2_RX_DMA_BUFFER_SIZE,
                         spi2_tx_dma_buffer, SPI2_TX_DMA_BUFFER_SIZE);
#endif
  /*----------------------------------------
 *             SPI3 Object
 *-----------------------------------------*/
#if SPI3_ENABLE
  #if SPI3_RX_DMA_ENABLE
  static uint8_t spi3_rx_dma_buffer[SPI3_RX_DMA_BUFFER_SIZE];
#else
  static uint8_t *spi3_rx_dma_buffer = nullptr;
#endif
#if SPI3_TX_DMA_ENABLE
  static uint8_t spi3_tx_dma_buffer[SPI3_TX_DMA_BUFFER_SIZE];
#else
  static uint8_t *spi3_tx_dma_buffer = nullptr;
#endif
  static SPI_Object spi3(SPI3, SPI3_RX_DMA_CH, SPI3_TX_DMA_CH,
                         spi3_rx_dma_buffer, SPI3_RX_DMA_BUFFER_SIZE,
                         spi3_tx_dma_buffer, SPI3_TX_DMA_BUFFER_SIZE);
#endif
  /*----------------------------------------
 *             SPI4 Object
 *-----------------------------------------*/
#if SPI4_ENABLE
#if SPI4_RX_DMA_ENABLE
  static uint8_t spi4_rx_dma_buffer[SPI4_RX_DMA_BUFFER_SIZE];
#else
  static uint8_t *spi4_rx_dma_buffer = nullptr;
#endif
#if SPI4_TX_DMA_ENABLE
  static uint8_t spi4_tx_dma_buffer[SPI4_TX_DMA_BUFFER_SIZE];
#else
  static uint8_t *spi4_tx_dma_buffer = nullptr;
#endif
  static SPI_Object spi4(SPI4, SPI4_RX_DMA_CH, SPI4_TX_DMA_CH,
                         spi4_rx_dma_buffer, SPI4_RX_DMA_BUFFER_SIZE,
                         spi4_tx_dma_buffer, SPI4_TX_DMA_BUFFER_SIZE);
#endif

/*
*/
bool HAL_SPI::init(uint32_t cfg0)
{
  uint8_t rx_nvic_irqn = 0;
  uint8_t tx_nvic_irqn = 0;
  uint8_t nvic_prio = 0;
  
  cfg = cfg0;
  uint32_t tmp = SPI_CFG_EXTRACT(cfg, DATA);
  if(tmp == SPI_DATA(8B)) {
    data_bits = 8;
  } else {
    data_bits = 16;
  }
  
  tmp = SPI_CFG_EXTRACT(cfg, PORT);
  if(tmp == 0) {  //No port
   return false;
  }
#if SPI1_ENABLE
  else if(tmp == SPI_PORT(1)) {
    spi1.data_bits = data_bits;
    port = (uint32_t)&spi1;
    nvic_prio = NVIC_IRQ_SPI1_PRIORITY;
    //Rx
#if SPI1_RX_DMA_ENABLE
    spi1.dma_rx_config();
    rx_nvic_irqn = SPI1_RX_DMA_CH_IRQN;
#endif
    //Tx
#if SPI1_TX_DMA_ENABLE
    spi1.dma_tx_config();
    tx_nvic_irqn = SPI1_TX_DMA_CH_IRQN;
#endif
  }
#endif
#if SPI2_ENABLE  
  else if(tmp == SPI_PORT(2)) {
    spi2.data_bits = data_bits;
    port = (uint32_t)&spi2;
    nvic_prio = NVIC_IRQ_SPI2_PRIORITY;
    //Rx
#if SPI2_RX_DMA_ENABLE
    spi2.dma_rx_config();
    rx_nvic_irqn = SPI2_RX_DMA_CH_IRQN;
#endif
    //Tx
#if SPI2_TX_DMA_ENABLE
    spi2.dma_tx_config();
    tx_nvic_irqn = SPI2_TX_DMA_CH_IRQN;
#endif
  }
#endif
#if SPI3_ENABLE 
  else if(tmp == SPI_PORT(3)) {
    spi3.data_bits = data_bits;
    port = (uint32_t)&spi3;
    nvic_prio = NVIC_IRQ_SPI3_PRIORITY;
    //Rx
#if SPI3_RX_DMA_ENABLE
    spi3.dma_rx_config();
    rx_nvic_irqn = SPI3_RX_DMA_CH_IRQN;
#endif
    //Tx
#if SPI3_TX_DMA_ENABLE
    spi3.dma_tx_config();
    tx_nvic_irqn = SPI3_TX_DMA_CH_IRQN;
#endif
  }
#endif
#if SPI4_ENABLE
  else if(tmp == SPI_PORT(4)) {
    spi4.data_bits = data_bits;
    port = (uint32_t)&spi4;
    nvic_prio = NVIC_IRQ_SPI4_PRIORITY;
    //Rx
#if SPI4_RX_DMA_ENABLE
    spi4.dma_rx_config();
    rx_nvic_irqn = SPI4_RX_DMA_CH_IRQN;
#endif
    //Tx
#if SPI4_TX_DMA_ENABLE
    spi4.dma_tx_config();
    tx_nvic_irqn = SPI4_TX_DMA_CH_IRQN;
#endif
  }
#endif
  else if(port == 0) {
    return false;
  }
  
  if(!config(cfg)) {
    return false;
  }
  
  //NVIC config
  NVIC_InitTypeDef   NVIC_InitStructure;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = nvic_prio;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  //rx
  if(rx_nvic_irqn > 0) {
    NVIC_InitStructure.NVIC_IRQChannel = rx_nvic_irqn;
    NVIC_Init(&NVIC_InitStructure);
  }
  //tx
  if(tx_nvic_irqn > 0) {
    NVIC_InitStructure.NVIC_IRQChannel = tx_nvic_irqn;
    NVIC_Init(&NVIC_InitStructure);
  }

  return true;
}
/*
*/
bool HAL_SPI::config(uint32_t cfg0)
{
  cfg &= ~SPI_CFG_MASK;
  cfg |= cfg0 & SPI_CFG_MASK;
  return ((SPI_Object*)port)->config(cfg);
}

/*
*/
bool HAL_SPI::set_brp(uint32_t brp)
{
  cfg &= ~(SPI_BRP_MASK << SPI_BRP_POS);
  cfg |= brp & (SPI_BRP_MASK << SPI_BRP_POS);
  return ((SPI_Object*)port)->config(cfg);
}
/*
*/
int HAL_SPI::transfer(uint8_t *tx_buffer, uint8_t *rx_buffer, uint32_t num)
{
  SPI_Object *spi = (SPI_Object*)port;
  if(port) {
    return spi->transfer(tx_buffer, rx_buffer, num);
  } else {
    return -1;
  }
}
/*
*/
int HAL_SPI::read(uint8_t *buffer, uint32_t number)
{
  if(SPI_CFG_EXTRACT(cfg, WIRE) == SPI_WIRE(2L1D)) {
    mosi_pin->set_mode(GPIO_MODE_IN);
  }
  
  SPI_Object *spi = (SPI_Object*)port;
  if(spi->dma_rx_buffer == nullptr) { //normal mode
    return transfer(nullptr, buffer, number);
  } else if(!spi->rx_busy) { //DMA mode, have new data
    memcpy(buffer, spi->dma_rx_buffer, number);
    spi->dma_rx_start(number); //where rx_busy will be set true
    return number;
  }
  
  return 0;
}
/*
*/
int HAL_SPI::write(uint8_t *buffer, uint32_t number)
{
  if(SPI_CFG_EXTRACT(cfg, WIRE) == SPI_WIRE(2L1D)) {
    mosi_pin->set_mode(GPIO_MODE_AF);
  }
  
  SPI_Object *spi = (SPI_Object*)port;
  if(spi->dma_tx_buffer == nullptr) { //normal mode
    return transfer(buffer, nullptr,  number);
  } else if(!spi->tx_busy) {  //DMA mode
    memcpy(spi->dma_tx_buffer, buffer, number);
    spi->dma_tx_start(number); //where tx_busy will be set true
    return number;
  }
  
  return 0;
}
/*------------------------------------------------
 *             IRQHandler
 *------------------------------------------------*/
#ifdef __cplusplus
 extern "C" {
#endif

//SPI1
#if SPI1_ENABLE
//RX
#if SPI1_RX_DMA_ENABLE
void SPI1_RX_DMA_CH_IRQH()
{
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  if(DMA_GetITStatus(SPI1_RX_DMA_IT_TC))
  {
    DMA_ClearITPendingBit(SPI1_RX_DMA_IT_TC);
    spi1.dma_rx_end();
  }
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}   
#endif
//TX
#if SPI1_TX_DMA_ENABLE
void SPI1_TX_DMA_CH_IRQH()
{
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  if(DMA_GetITStatus(SPI1_TX_DMA_IT_TC))
  {
    DMA_ClearITPendingBit(SPI1_TX_DMA_IT_TC);
    spi1.dma_tx_end();
  }
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif
#endif

//SPI2
#if SPI2_ENABLE
//RX
#if SPI2_RX_DMA_ENABLE
void SPI2_RX_DMA_CH_IRQH()
{
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  if(DMA_GetITStatus(SPI2_RX_DMA_IT_TC))
  {
    DMA_ClearITPendingBit(SPI2_RX_DMA_IT_TC);
    spi2.dma_rx_end();
  }
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}   
#endif
//TX
#if SPI2_TX_DMA_ENABLE
void SPI2_TX_DMA_CH_IRQH()
{
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  if(DMA_GetITStatus(SPI2_TX_DMA_IT_TC))
  {
    DMA_ClearITPendingBit(SPI2_TX_DMA_IT_TC);
    spi2.dma_tx_end();
  }
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif
#endif

//SPI3
#if SPI3_ENABLE
//RX
#if SPI3_RX_DMA_ENABLE
void SPI3_RX_DMA_CH_IRQH()
{
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  if(DMA_GetITStatus(SPI3_RX_DMA_IT_TC))
  {
    DMA_ClearITPendingBit(SPI3_RX_DMA_IT_TC);
    spi3.dma_rx_end();
  }
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}   
#endif
//TX
#if SPI3_TX_DMA_ENABLE
void SPI3_TX_DMA_CH_IRQH()
{
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  if(DMA_GetITStatus(SPI3_TX_DMA_IT_TC))
  {
    DMA_ClearITPendingBit(SPI3_TX_DMA_IT_TC);
    spi3.dma_tx_end();
  }
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif
#endif

//SPI4
#if SPI4_ENABLE
//RX
#if SPI4_RX_DMA_ENABLE
void SPI4_RX_DMA_CH_IRQH()
{
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  if(DMA_GetITStatus(SPI4_RX_DMA_IT_TC))
  {
    DMA_ClearITPendingBit(SPI4_RX_DMA_IT_TC);
    spi4.dma_rx_end();
  }
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}   
#endif
//TX
#if SPI4_TX_DMA_ENABLE
void SPI4_TX_DMA_CH_IRQH()
{
#if defined(USING_RT_THREAD)
  rt_interrupt_enter();
#endif
  
  if(DMA_GetITStatus(SPI4_TX_DMA_IT_TC))
  {
    DMA_ClearITPendingBit(SPI4_TX_DMA_IT_TC);
    spi4.dma_tx_end();
  }
  
#if defined(USING_RT_THREAD)
  rt_interrupt_leave();
#endif
}
#endif
#endif
/*
*/
#ifdef __cplusplus
}
#endif  
  
  
  
  
  

